// Copyright (C) 2010 and onwards Harik Shazeer Labs
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Authors: Noam Shazeer and Georges Harik

#include "jobqueue.h"

JobQueue * G_JQ;

void InitJobQueue(int num_threads) {
  G_JQ = new JobQueue();
  G_JQ->LaunchThreads(num_threads);
}

extern JobQueue * G_JQ;

void * JobQueueLaunchThread(void *q) {
  //cout << "Entered JobQueueLaunchThread" << endl;
  JobQueue * jq = (JobQueue *)q;
  jq->ThreadBody();
  return NULL;
}

struct ZeroTask : public JobQueue::Task {
  ZeroTask(void *location, uint64 size) {
    location_ = location; 
    size_ = size;
  }
  void Run() {
    bzero(location_, size_);
  }
  void *location_;
  uint64 size_;
};

struct CopyTask : public JobQueue::Task {
  CopyTask(void *destination, void *source, uint64 size) {
    destination_ = destination;
    source_ = source;
    size_ = size;
  }
  void Run() {
    memcpy(destination_, source_, size_);
  }
  void *destination_;
  void *source_;
  uint64 size_;
};

void JobQueueZero(JobQueue * jq, void * location, uint64 bytes) {
  char * loc = (char *) location;
  if (bytes < 1000000) {
    bzero(loc, bytes);
    return;
  }
  cout << "Long zero bytes = " << bytes << endl;
  uint64 num_shards = jq->NumThreads();
  JobQueue::Job j(jq);
  for (uint64 i=0; i<num_shards; i++) {
    uint64 begin = ShardBegin(bytes, num_shards, i);
    uint64 size = ShardEnd(bytes, num_shards, i) - begin;
    j.AddTask(new ZeroTask(loc + begin, size));
  }
  j.Wait();
}

void JobQueueCopy
(JobQueue * jq, void * destination, void *source, uint64 bytes){
  char * dest = (char *)destination;
  char * src = (char *) source;
  if (bytes < 1000000) {				
    memcpy(destination, source, bytes);
    return;
  }
  cout << "Long copy bytes = " << bytes << endl;
  uint64 num_shards = jq->NumThreads();
  JobQueue::Job j(jq);
  for (uint64 i=0; i<num_shards; i++) {
    uint64 begin = ShardBegin(bytes, num_shards, i);
    uint64 size = ShardEnd(bytes, num_shards, i) - begin;
    j.AddTask(new CopyTask(dest + begin, src+begin, size));
  }
  j.Wait();
}
